﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;

namespace OverStore.Runtime.ObjectRepository.ErrorTransformer
{
    /// <summary>
    /// Uses set of <see cref="MatchCase"/> objects to rethrow exceptions.
    /// </summary>
    /// <typeparam name="TInstance">The type of the instance.</typeparam>
    public sealed class MatchErrorTransformer<TInstance> : IErrorTransformer<TInstance>
        where TInstance : class
    {
        private readonly IEnumerable<MatchCase> _MatchCases;

        /// <summary>
        /// Initializes a new instance of the <see cref="MatchErrorTransformer&lt;TInstance&gt;"/> class.
        /// </summary>
        /// <param name="matchCases">The match cases.</param>
        public MatchErrorTransformer(IEnumerable<MatchCase> matchCases)
        {
            if (Object.ReferenceEquals(matchCases, null))
                throw new ArgumentNullException("matchCases");
            _MatchCases = matchCases.ToArray();
        }

        /// <summary>
        /// 	<para>
        /// Analyses specified exception attributes, such as type, message, inner exceptions etc. and
        /// rethrows new <see cref="OverStore.Runtime.PersistingRuntimeException"/> with different message.
        /// </para>
        /// 	<para>
        /// If specified exception can't be processed, method should do nothing, and calling code
        /// must rethrow catched exception using <c>throw;</c> statement.
        /// </para>
        /// </summary>
        /// <param name="ex">Exception to analyze.</param>
        /// <exception cref="ArgumentNullException"><paramref name="ex"/> is null reference.</exception>
        /// <exception cref="OverStore.Runtime.PersistingRuntimeException">Argument exception is successfuly analyzed and rethrown.</exception>
        public void Transform(PersistingRuntimeException ex)
        {
            Exception baseException = ex;
            int counter = 0;
            while (true)
            {
                counter++;
                if (ex.InnerException == null)
                    break;
                baseException = ex.InnerException;

                if (baseException.GetType() != typeof(PersistingRuntimeException) ||
                    counter > 10)
                    break;
            }
            foreach (var matchCase in _MatchCases)
                matchCase.Process(baseException);
        }
    }
}
